import Vue from 'vue'
import VueApollo, { ApolloProvider } from 'vue-apollo'
import {
  createApolloClient,
  restartWebsockets
  //@ts-ignore
} from 'vue-cli-plugin-apollo/graphql-client'
import ApolloClient from 'apollo-client'
import { onError } from 'apollo-link-error'

import { InMemoryCache } from 'apollo-cache-inmemory'
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'
import introspectionQueryResultData from '@/fragmentTypes.json'
const fragmentMatcher = new IntrospectionFragmentMatcher({
  introspectionQueryResultData
})

// Install the vue plugin

Vue.use(VueApollo)

// Name of the localStorage item
const AUTH_TOKEN = 'apollo-token'

// Http endpoint
let httpEndpoint =
  process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:9090/graphql'
let wsEndpoint = process.env.VUE_APP_GRAPHQL_WS || 'ws://localhost:9090/graphql'

const defaultOptions = {
  // You can use `https` for secure connection (recommended in production)
  httpEndpoint,
  // You can use `wss` for secure connection (recommended in production)
  // Use `null` to disable subscriptions
  wsEndpoint,
  // LocalStorage token
  tokenName: AUTH_TOKEN,
  // Enable Automatic Query persisting with Apollo Engine
  persisting: false,
  // Use websockets for everything (no HTTP)
  // You need to pass a `wsEndpoint` for this to work
  websocketsOnly: false,
  // Is being rendered on the server?
  ssr: false,

  // Override default apollo link
  // note: don't override httpLink here, specify httpLink options in the
  // httpLinkOptions property of defaultOptions.
  // link: errorHandler,

  // Override default cache
  cache: new InMemoryCache({ fragmentMatcher }),

  // Override the way the Authorization header is set
  getAuth: tokenName => {
    // get the authentication token from local storage if it exists
    const token = localStorage.getItem(tokenName)
    // return the headers to the context so httpLink can read them
    return token || ''
  },

  // Additional ApolloClient options
  // apollo: { ... }
  apollo: {
    fetchOptions: {
      mode: 'no-cors'
    }
  }

  // Client local data (see apollo-link-state)
  // clientState: { resolvers: { ... }, defaults: { ... } }
}

// Call this in the Vue app file
export function createProvider(
  options = {},
  networkErrHandler,
  gqlErrorHandler
) {
  const errorHandler = onError(
    ({ networkError, graphQLErrors, response, operation }) => {
      if (networkError) {
        networkErrHandler(networkError)
      }
      // throw errors
    }
  )

  const { apolloClient, wsClient } = createApolloClient({
    ...defaultOptions,
    ...options,
    link: errorHandler
  })
  apolloClient.wsClient = wsClient

  // Create vue apollo provider
  const apolloProvider = new VueApollo({
    defaultClient: apolloClient,
    defaultOptions: {
      $query: {
        // fetchPolicy: 'cache-and-network',
      }
    },
    errorHandler(error) {
      // eslint-disable-next-line no-console
      console.log(
        '%cError',
        'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;',
        error.message
      )

      // if errHandler return true, means the error is handled
      // Handler from top to bottom
      return gqlErrorHandler(error)
    }
  })

  return apolloProvider
}

// Manually call this when user log in
export async function onLogin(apolloClient) {
  // if (typeof localStorage !== 'undefined' && token) {
  //   localStorage.setItem(AUTH_TOKEN, token)
  // }
  if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
  try {
    await apolloClient.resetStore()
  } catch (e) {
    // eslint-disable-next-line no-console
    console.log('%cError on cache reset (login)', 'color: orange;', e.message)
  }
}

// Manually call this when user log out
export async function onLogout(apolloClient) {
  // if (typeof localStorage !== 'undefined') {
  //   localStorage.removeItem(AUTH_TOKEN)
  // }
  if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
  try {
    await apolloClient.resetStore()
  } catch (e) {
    // eslint-disable-next-line no-console
    console.log('%cError on cache reset (logout)', 'color: orange;', e.message)
  }
}
